package com.luoye.audiodemo.weight

import android.content.Context
import android.opengl.EGL14
import android.opengl.GLES20
import android.util.AttributeSet
import android.view.Surface
import android.view.SurfaceHolder
import android.view.SurfaceView
import com.blankj.utilcode.util.LogUtils
import com.luoye.audiodemo.R
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.Closeable
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import javax.microedition.khronos.egl.EGL10
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.egl.EGLContext
import javax.microedition.khronos.egl.EGLDisplay
import javax.microedition.khronos.egl.EGLSurface
import kotlin.coroutines.CoroutineContext

/**
 * 矩形
 */
class MyGLSurfaceView2 @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAtt: Int = -1
) : SurfaceView(context, attrs, defStyleAtt), SurfaceHolder.Callback {
    init {
        holder.addCallback(this)
    }

    private val liveHandler = CoroutineExceptionHandler { _, e ->
        // 处理异常
        LogUtils.e(e)
    }
    private val scope = UploadCoroutineScope(SupervisorJob() + Dispatchers.IO + liveHandler)
    override fun surfaceCreated(holder: SurfaceHolder) {
        LogUtils.e("创建")
    }


    override fun surfaceChanged(holder: SurfaceHolder, format: Int, w: Int, h: Int) {
        LogUtils.e("改变")
        initEgl(holder.surface)
        initOpenGl()
        GLES20.glViewport(0, 0, width, height)
        // 协程
        scope.launch {
            while (true) {
                withContext(Dispatchers.Main) {
                    // 这个几行代码必须在主线程中调用才可以生效。
                    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT)
                    GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f)
                    //
                    GLES20.glUseProgram(program!!);
                    //绘制绿色
                    GLES20.glUniform4f(fPosition!!, 1f, 0f, 1f, 1f);
                    //使能顶点属性数组，使之有效
                    GLES20.glEnableVertexAttribArray(vPosition!!);
                    //使能之后，为顶点属性赋值，绑定顶点坐标
                    GLES20.glVertexAttribPointer(
                        vPosition!!,
                        2,
                        GLES20.GL_FLOAT,
                        false,
                        8,
                        vertexBuffer
                    );
                    //绘制图形
                    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);//


                    mEgl?.apply {
                        // 刷新。
                        val swap = eglSwapBuffers(mEglDisplay, mEglSurface)
                    }
                }
                // 20 到200 都行。
                delay(200)
            }
        }
    }

    override fun surfaceDestroyed(holder: SurfaceHolder) {
        LogUtils.e("销毁")
    }

    private var mEgl: EGL10? = null //EGL实例

    private var mEglDisplay: EGLDisplay? = null //默认的显示设备

    private var mEglContext: EGLContext? = null //EGL上下文

    private var mEglSurface: EGLSurface? = null //EGLSurface


    var program: Int? = null
    var vPosition: Int? = null
    var fPosition: Int? = null
    fun initOpenGl() {

        //        -----------------------------------------片元顶点---------------------
        val vertexSharder = readRawTextFile(context, R.raw.screen_vert)
        val vShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER)
        GLES20.glShaderSource(vShader, vertexSharder)
        GLES20.glCompileShader(vShader)
        //查看配置 是否成功
        var status = IntArray(1)
        GLES20.glGetShaderiv(vShader, GLES20.GL_COMPILE_STATUS, status, 0)
        if (status[0] != GLES20.GL_TRUE) {
            //失败
            throw IllegalStateException("load fragment shader:" + GLES20.glGetShaderInfoLog(vShader))
        }
        //        -----------------------------------------片元着色器----------------------
        val fragSharder = readRawTextFile(context, R.raw.screen_frag_color)
        val fShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER)
        GLES20.glShaderSource(fShader, fragSharder)
        GLES20.glCompileShader(fShader)
        status = IntArray(1)
        GLES20.glGetShaderiv(fShader, GLES20.GL_COMPILE_STATUS, status, 0)
        if (status[0] != GLES20.GL_TRUE) {
            //失败
            throw IllegalStateException("load fragment shader:" + GLES20.glGetShaderInfoLog(fShader))
        }
        //----------------------创建一个总程序------------exe------
        program = GLES20.glCreateProgram()
        //         加载顶点程序
        GLES20.glAttachShader(program!!, vShader)
        //         加载片元程序
        GLES20.glAttachShader(program!!, fShader)

        //链接着色器程序  gou 激活状态
        GLES20.glLinkProgram(program!!)
        //从渲染程序中得到着顶点色器中的属性
        vPosition = GLES20.glGetAttribLocation(program!!, "vPosition");
        //从渲染程序中得到片元着色器中的属性
        fPosition = GLES20.glGetUniformLocation(program!!, "f_Color");
    }

    // 顶点坐标。
    val vertexBuffer: FloatBuffer by lazy {
        val vertexData = floatArrayOf(
            -1f, 0f,
            0f, 1f,
            0f,-1f,
            1f, 0f
        )
        val buffer = ByteBuffer.allocateDirect(vertexData.size * 4).order(ByteOrder.nativeOrder())
            .asFloatBuffer().put(vertexData)
        buffer.position(0)
        buffer
    }

    fun initEgl(surface: Surface) {

        //1.获取 Egl实例
        mEgl = EGLContext.getEGL() as EGL10

        //2.获取一个默认的显示设备
        mEglDisplay = mEgl!!.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)
        if (mEglDisplay === EGL10.EGL_NO_DISPLAY) {
            throw RuntimeException("get EGL_DEFAULT_DISPLAY error")
        }

        //3.初始化默认显示设备
        val version = IntArray(2)
        if (!mEgl!!.eglInitialize(mEglDisplay, version)) {
            throw RuntimeException("init EGL_DEFAULT_DISPLAY error")
        }
        //4.设置显示设备的属性
        val attrs = intArrayOf(
            EGL10.EGL_RED_SIZE, 8,
            EGL10.EGL_GREEN_SIZE, 8,
            EGL10.EGL_BLUE_SIZE, 8,
            EGL10.EGL_ALPHA_SIZE, 8,
            EGL10.EGL_DEPTH_SIZE, 8,
            EGL10.EGL_STENCIL_SIZE, 8,
            EGL10.EGL_RENDERABLE_TYPE, 4,
            EGL10.EGL_NONE
        )
        val num_config = IntArray(1)
        require(
            mEgl!!.eglChooseConfig(
                mEglDisplay,
                attrs,
                null,
                1,
                num_config
            )
        ) { "set eglChooseConfig failed" }
        val numConfigs = num_config[0]
        require(numConfigs > 0) { "No configs match configSpec" }

        //5.从系统中获取对应属性的配置
        val configs = arrayOfNulls<EGLConfig>(numConfigs)
        require(
            mEgl!!.eglChooseConfig(
                mEglDisplay,
                attrs,
                configs,
                numConfigs,
                num_config
            )
        ) { "eglChooseConfig#2 failed" }

        //6.创建 EglContext
        val attr_list = intArrayOf(
            EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL10.EGL_NONE
        )
        mEglContext = mEgl!!.eglCreateContext(
            mEglDisplay,
            configs[0], EGL10.EGL_NO_CONTEXT, attr_list
        )
        //7.创建渲染的 Surface,最后一个参数传空
        mEglSurface = mEgl!!.eglCreateWindowSurface(mEglDisplay, configs[0], surface, null)

        //8、绑定 EglContext和 Surface到显示设备中
        if (!mEgl!!.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
            throw RuntimeException("eglMakeCurrent failed")
        }
    }
}


